/*
Copyright 2011 Mary Suárez Machado

Este programa es de software libre: usted puede redistribuirlo y/o modificarlo según los términos de la Licencia de Gran pública de GNU como publicado por la Fundación de Software Libre, versión 3 de la Licencia, (o en su opción) cualquier versión posterior.

 Este programa es distribuido en la esperanza que será útil, pero SIN CUALQUIER GARANTÍA; sin aún la garantía implícita de VALOR COMERCIAL O SALUD PARA UN OBJETIVO PARTICULAR. Mirar la Licencia de Gran pública de GNU para más detalles.
*/


 /**
 *@file VectorBits.cpp
 *@brief Implementaciones de las funciones del módulo VectorBits
 *@author Mary Carmen Suarez
 *
 */

#include <iostream>
#include <cassert>
#include <cstring>
#include <VectorBits.h>

using namespace std;

VectorBits :: VectorBits()
{
	v=0;
	nbits=0;
	reservados=0;
}

VectorBits :: VectorBits (int valor, int n)
{
	nbits=0;
	reservados=0;
	v=0;
	for (int i=0; i<n;i++)
	{
		int resto = valor%2;
		*this += resto;
		valor=valor/2;
	}
}

VectorBits :: VectorBits(const VectorBits & orig)
{
	nbits=orig.nbits;
	reservados=orig.reservados;
	if (orig.v != 0)
	{
		v=new unsigned char[orig.reservados];
		for (int i=0; i<orig.reservados; i++)
			v[i]=orig.v[i];
	}
	else v=0;
}

VectorBits :: ~VectorBits()
{
	if (v != 0)
		delete [] v;
}

VectorBits & VectorBits :: operator= (const VectorBits & orig)
{
	if (this != &orig)
	{
		if (v != 0)
			delete [] v;
		if (orig.v != 0)
		{
			v=new unsigned char[orig.reservados];
			for (int i=0; i<orig.reservados; i++)
				v[i]=orig.v[i];		
		}
		else v=0;
		nbits=orig.nbits;
		reservados=orig.reservados;
	}
	return *this;
}

void VectorBits :: SetVector (bool dato, int pos)
{
	assert (pos>=0 && pos <nbits); 
	int pbytes = pos/8;
	int pbits = pos%8;
	if (dato==1)
		v[pbytes]|=(1<<pbits);
	else v[pbytes]&= ~(1<<pbits);
}

bool VectorBits :: GetVector (int pos) const
{
	assert (pos>=0 && pos <nbits); 
	int pbytes = pos/8;
	int pbits = pos%8;
	return (v[pbytes]&(1<<pbits));
}

int VectorBits :: GetNbits () const
{
	return nbits;
}

bool VectorBits :: operator== (const VectorBits & orig) const
{
	if (nbits != orig.nbits)
		return false;
	else
	{
		int tam=(nbits+7)/8;
		for (int i=0; i<tam; i++)
			if (v[i] != orig.v[i])
				return false;
		return true;
	}
}

bool VectorBits :: operator!= (const VectorBits & orig) const
{
	if (*this == orig) return false;
	else return true;
}

VectorBits & VectorBits :: operator+= (bool dato)
{
	int pbytes = nbits/8;

	if (pbytes == reservados)
		Resize(reservados+1);
	nbits++;
	SetVector(dato,nbits-1);
	return *this;
}

VectorBits & VectorBits :: operator+= (const VectorBits & orig)
{
	VectorBits aux;
	aux.nbits=nbits+orig.nbits;
	aux.reservados=(aux.nbits+7)/8;
	aux.v=new unsigned char [aux.reservados];
	for (int i=0;i<aux.reservados;++i) 
      aux.v[i]=0;
	memcpy (aux.v,this->v,(nbits+7)/8);
	int j=0;
	for (int i=nbits; j< orig.nbits; i++,j++)
	{
		aux.SetVector(orig.GetVector(j),i);
	}

	swap (nbits,aux.nbits);
	swap (reservados,aux.reservados);
	swap (v, aux.v);
	return *this;
}

int VectorBits :: GetReservados () const
{
	return reservados;
}

ostream & operator<< (ostream& os, const VectorBits & vector)
{
	int usados=vector.GetNbits();
	for (int i=0; i< usados; i++)
		os<<vector.GetVector(i);
	return os;
}

istream & operator>> (istream& is, VectorBits & vector)
{
	vector=VectorBits();
	char dato;
	while (is.peek()=='1' || is.peek()=='0')
	{
		dato=is.get();
		if (dato == '1')
			vector += 1;
		else vector += 0;
	}
	return is;
}

void VectorBits :: Resize (int n)
{
	assert (n>=0);
	if (n==0)
	{
		if (v != 0)
		{
			delete [] v;
			v =0;
		}
	}
	else
	{
		if (reservados == 0)
		{
			v=new unsigned char[n];
			for (int i=0; i<n; i++)
				v[i]=0;
		}
		else
		{
			unsigned char *aux=new unsigned char[n];
			for (int i=0; i<n; i++)
				aux[i]=0;
			if (n >= reservados)
				for (int i=0; i<reservados;i++)
					aux[i]=v[i];
			else 
				for (int i=0; i<n;i++)
					aux[i]=v[i];
			delete [] v;
			v = aux;		
		}
	}
	reservados=n;
}

void VectorBits :: Invertir()
{
	bool izq,der;
	for (int i=0; i<nbits/2; i++)
	{
		izq = GetVector(nbits-1-i);
		der = GetVector(i);
		SetVector(der,nbits-1-i);
		SetVector(izq,i);
	}
}

void VectorBits :: Salvar (ostream & os)
{
	os.write( (char*)v, (nbits+7)/8 );
}

void VectorBits :: Leer (istream & is, unsigned int tam)
{
	reservados=tam;
	nbits= tam*8;
	delete [] v;
	v = new unsigned char [tam];
	is.read ((char*)v, tam);
}

int VectorBits :: NumeroEntero ()
{
	int nbyte = (nbits+7)/8;
	unsigned int val = 0;
	for (int i=0; i<nbyte; i++)
		val=val | (v[i]<<(8*i) );
	return val; 
}
